define( 
    
    [ 'three', 'curveExtras', 'util' ],
    
    function( THREE, undefined, util ) {

        var minecraftPlayer = function( p ) {

            this.options = p;

            this.skinMaterial = new THREE.MeshBasicMaterial( { color: new THREE.Color( 0xeebb99 ) } ),

            this.createHeadObjects().createUpperBodyObjects().createLegObjects();

            this.playerObj = new THREE.Object3D();
       
            this.playerObj.add( this.legObjects.leftLegObj );
            this.playerObj.add( this.legObjects.rightLegObj );
            this.playerObj.add( this.upperBodyObjects.group );
            this.playerObj.add( this.headObjects.group );

            //playerGroup.scale.setLength( p.scaleLength );
            //playerModel.position.set( p.player.position.x, p.player.position.y, p.player.position.z );

            return this;
        }

        minecraftPlayer.prototype = {

            createHeadObjects: function() {

                this.headObjects = {

                    group: new THREE.Object3D(),
                    headShape: new THREE.CubeGeometry( this.options.head.size.x, this.options.head.size.y, this.options.head.size.z ),
                    eyeShape: new THREE.SphereGeometry( this.options.eye.size.radius, this.options.eye.size.widthSegments, this.options.eye.size.heightSegments ),
                    noseShape:
                        new THREE.CylinderGeometry( this.options.nose.frontRadius,
                                                    this.options.nose.backRadius,
                                                    this.options.nose.length,
                                                    this.options.nose.radialSegments,
                                                    this.options.nose.heightSegments,
                                                    this.options.nose.openEnded ),

                    eyeMaterial: new THREE.MeshBasicMaterial( { color: new THREE.Color( 0x87421F ) } ),
                    noseMaterial: new THREE.MeshBasicMaterial( { color: new THREE.Color( 0x000000 ) } ),
                    mouthMaterial: new THREE.LineBasicMaterial( { color: new THREE.Color( 0xFF6666 ) } ),
                    hairMaterial: new THREE.MeshBasicMaterial( { color: new THREE.Color( 0xA52A2A ) } )

                };

                var pathSegments = [ ];

                for( var i = 0, ii = this.options.mouth.points.length; i < ii; i++ ) {

                    pathSegments.push(
                        new THREE.Vector3(
                            this.options.mouth.points[i].x,
                            this.options.mouth.points[i].y,
                            this.options.mouth.points[i].z ) );
                }

                var spline = new THREE.SplineCurve3( pathSegments );
                var splinePoints = spline.getPoints( this.options.mouth.numberOfPoints );
                var geometry = new THREE.Geometry();

                for( var i = 0, ii = splinePoints.length; i < ii; i++ ) {

                    geometry.vertices.push( splinePoints[i] );  
                }

                this.headObjects.mouthShape = geometry;

                generateTextureBase = function() {

                    var canvas = document.createElement( 'canvas' );
                    canvas.width = 512;
                    canvas.height = 512;

                    var context = canvas.getContext( '2d' );

                    for ( var i = 0; i < 20000; i ++ ) {

                        context.fillStyle = 'rgba(0,' + Math.floor( Math.random() * 64 + 32 ) + ',16,1)';
                        context.beginPath();
                        context.arc( Math.random() * canvas.width, Math.random() * canvas.height, Math.random() * 1 + 0.5, 0, Math.PI * 2, true );
                        context.fill();

                    }
                    
                    context.globalAlpha = 0.075;
                    context.globalCompositeOperation = 'lighter';

                    return canvas;

                }

                generateTextureLevel = function( texture ) {

                    texture.getContext( '2d' ).drawImage( texture, 0, 0 );

                    var canvas = document.createElement( 'canvas' );
                    canvas.width = texture.width;
                    canvas.height = texture.height;

                    canvas.getContext( '2d' ).drawImage( texture, 0, 0 );

                    return canvas;
                }
                
                var bitmap = generateTextureBase();
                var geometry = new THREE.PlaneGeometry( 8, 8 );

                levels = [];

                for ( var i = 0; i < 5; i ++ ) {

                    mesh = levels[i] =
                        new THREE.Mesh( geometry,
                                        new THREE.MeshBasicMaterial( {
                                            map: new THREE.Texture( generateTextureLevel( bitmap ) ),
                                            transparent: true,
                                            depthWrite: false,
                                            depthTest: false } ) );

                    mesh.material.map.needsUpdate = true;

                    mesh.position.y = 6 + ( i * 0.1 );
                    mesh.rotation.x = util.degreesToRadians( 90 );

                    this.headObjects.group.add( mesh );
                }

                var backOfHead = new THREE.PlaneGeometry( 8, 6 );
                var sideHead = new THREE.PlaneGeometry( 6, 2 );
                var burns = new THREE.PlaneGeometry( 1, 4 );
                var front = new THREE.PlaneGeometry( 8, 0.5 );

                backLevels = [];
                rightLevels = [];
                leftLevels = [];

                for ( var i = 0; i < 5; i ++ ) {

                    mesh = backLevels[i] =
                        new THREE.Mesh( backOfHead,
                                        new THREE.MeshBasicMaterial( {
                                            map: new THREE.Texture( generateTextureLevel( bitmap ) ),
                                            transparent: true,
                                            depthWrite: false,
                                            depthTest: false } ) );

                    mesh.material.map.needsUpdate = true;
                    
                    mesh.position.y = 3;
                    mesh.position.x = -4 - ( i * 0.05 );
                    mesh.rotation.x = util.degreesToRadians( 90 );
                    mesh.rotation.z = util.degreesToRadians( 90 );
                    mesh.rotation.y = util.degreesToRadians( 270 );

                    this.headObjects.group.add( mesh );

                    rightLevels[i] = 
                        new THREE.Mesh( sideHead,
                                        new THREE.MeshBasicMaterial( {
                                            map: new THREE.Texture( generateTextureLevel( bitmap ) ),
                                            transparent: true,
                                            depthWrite: false,
                                            depthTest: false } ) );

                    rightLevels[i].material.map.needsUpdate = true;

                    leftLevels[i] = rightLevels[i].clone();

                    leftLevels[i].position.x = -1;
                    leftLevels[i].position.y = 5;
                    leftLevels[i].position.z = -4 - ( i * 0.05 );
                    leftLevels[i].rotation.x = util.degreesToRadians( 180 );
                    
                    rightLevels[i].position.x = -1;
                    rightLevels[i].position.y = 5;
                    rightLevels[i].position.z = 4 + ( i * 0.05 );
                    
                    this.headObjects.group.add( leftLevels[i] );
                    this.headObjects.group.add( rightLevels[i] );

                    burn = 
                        new THREE.Mesh( burns,
                                        new THREE.MeshBasicMaterial( {
                                            map: new THREE.Texture( generateTextureLevel( bitmap ) ),
                                            transparent: true,
                                            depthWrite: false,
                                            depthTest: false } ) );
                    
                    burn.material.map.needsUpdate = true;

                    otherBurn = burn.clone();

                    burn.position.x = 2.5;
                    burn.position.y = 4;
                    burn.position.z = -4 - ( i * 0.05 );
                    burn.rotation.x = util.degreesToRadians( 180 );
                    
                    this.headObjects.group.add( burn );

                    otherBurn.position.x = 2.5;
                    otherBurn.position.y = 4;
                    otherBurn.position.z = 4 + ( i * 0.05 );

                    this.headObjects.group.add( otherBurn );

                    burn = 
                        new THREE.Mesh( burns,
                                        new THREE.MeshBasicMaterial( {
                                            map: new THREE.Texture( generateTextureLevel( bitmap ) ),
                                            transparent: true,
                                            depthWrite: false,
                                            depthTest: false } ) );
                    
                    burn.material.map.needsUpdate = true;
                }
                
                this.headObjects.headObj = new THREE.Mesh( this.headObjects.headShape, this.skinMaterial );
                this.headObjects.headObj.position = new THREE.Vector3( this.options.head.position.x, this.options.head.position.y, this.options.head.position.z ),

                head = this.headObjects.headObj;
                headShape = this.headObjects.headShape;

                this.headObjects.leftEyeObj = new THREE.Mesh( this.headObjects.eyeShape, this.headObjects.eyeMaterial );
                this.headObjects.leftEyeObj.position = new THREE.Vector3( this.options.leftEye.position.x, this.options.leftEye.position.y, this.options.leftEye.position.z );

                this.headObjects.rightEyeObj = new THREE.Mesh( this.headObjects.eyeShape, this.headObjects.eyeMaterial );
                this.headObjects.rightEyeObj.position = new THREE.Vector3( this.options.rightEye.position.x, this.options.rightEye.position.y, this.options.rightEye.position.z );
                this.headObjects.noseObj = new THREE.Mesh( this.headObjects.noseShape, this.headObjects.noseMaterial );
                this.headObjects.noseObj.position = new THREE.Vector3( this.options.nose.position.x, this.options.nose.position.y, this.options.nose.position.z );
                
                this.headObjects.mouthObj = new THREE.Line( this.headObjects.mouthShape, this.headObjects.mouthMaterial );
                this.headObjects.mouthObj.position = new THREE.Vector3( this.options.mouth.position.x, this.options.mouth.position.y, this.options.mouth.position.z );
                this.headObjects.mouthObj.rotation.set( util.degreesToRadians( this.options.mouth.rotation.x ),
                                                        util.degreesToRadians( this.options.mouth.rotation.y ),
                                                        util.degreesToRadians( this.options.mouth.rotation.z ) );

                this.headObjects.group.add( this.headObjects.headObj );
                this.headObjects.group.add( this.headObjects.leftEyeObj );
                this.headObjects.group.add( this.headObjects.rightEyeObj );
                this.headObjects.group.add( this.headObjects.noseObj );
                this.headObjects.group.add( this.headObjects.mouthObj );

                this.headObjects.group.position = new THREE.Vector3( this.options.headGroup.position.x, this.options.headGroup.position.y, this.options.headGroup.position.z );

                return this;
            },

            createUpperBodyObjects: function() {

                this.upperBodyObjects = {

                    group: new THREE.Object3D(),
                    bodyShape: new THREE.CubeGeometry( this.options.body.size.x, this.options.body.size.y, this.options.body.size.z ),
                    armShape: new THREE.CubeGeometry( this.options.arm.size.x, this.options.arm.size.y, this.options.arm.size.z ),
                }
               
                this.upperBodyObjects.bodyObj = new THREE.Mesh( this.upperBodyObjects.bodyShape, this.skinMaterial );

                this.upperBodyObjects.leftArmObj = new THREE.Mesh( this.upperBodyObjects.armShape, this.skinMaterial );
                this.upperBodyObjects.leftArmObj.position =
                    new THREE.Vector3( this.options.leftArm.position.x, this.options.leftArm.position.y, this.options.leftArm.position.z );

                this.upperBodyObjects.leftArmObj.rotation.x = Math.PI/32;

                this.upperBodyObjects.rightArmObj = new THREE.Mesh( this.upperBodyObjects.armShape, this.skinMaterial );
                this.upperBodyObjects.rightArmObj.position =
                    new THREE.Vector3( this.options.rightArm.position.x, this.options.rightArm.position.y, this.options.rightArm.position.z );

                this.upperBodyObjects.rightArmObj.rotation.x = -Math.PI/32;

                this.upperBodyObjects.group.add( this.upperBodyObjects.bodyObj );
                this.upperBodyObjects.group.add( this.upperBodyObjects.leftArmObj );
                this.upperBodyObjects.group.add( this.upperBodyObjects.rightArmObj );

                return this;
            },

            createLegObjects: function( p ) {

                this.legObjects = {
                    
                    legShape: new THREE.CubeGeometry( this.options.leg.size.x, this.options.leg.size.y, this.options.leg.size.z )

                }

                this.legObjects.leftLegObj = new THREE.Mesh( this.legObjects.legShape, this.skinMaterial );
                this.legObjects.leftLegObj.position = new THREE.Vector3( this.options.leftLeg.position.x, this.options.leftLeg.position.y, this.options.leftLeg.position.z );
                
                this.legObjects.rightLegObj = new THREE.Mesh( this.legObjects.legShape, this.skinMaterial );
                this.legObjects.rightLegObj.position = new THREE.Vector3( this.options.rightLeg.position.x, this.options.rightLeg.position.y, this.options.rightLeg.position.z );

                return this;
            }
        };

        return minecraftPlayer;

} );
   
